package sf.database.jdbc.sql;

import sf.common.wrapper.Page;
import sf.database.template.TemplateRender;
import sf.database.util.DBUtils;
import sf.spring.util.Assert;
import sf.spring.util.CollectionUtils;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 根据模板的sql查询
 * @author sxf
 */
public class CrudTemplateSourceImpl implements CrudTemplateSourceInf {

    private CrudSqlInf cs = CrudSqlImpl.getInstance();

    @Override
    public int[] executeBatch(Connection conn, String sqlSource, List<Map<String, Object>> parameters) {
        List<Object[]> paras = new ArrayList<>();
        SQLContext one = getBatchSqlContextBySqlSource(sqlSource, parameters, paras);
        return cs.executeBatch(conn, one.getSql(), paras);
    }

    @Override
    public int[] executeBatch(Connection conn, String sqlSource, List<Map<String, Object>> parameters, boolean insertFast,
                              int batchSize, List<String> pkeys, List<Map<String, Object>> keyValues) {
        List<Object[]> paras = new ArrayList<>();
        SQLContext one = getBatchSqlContextBySqlSource(sqlSource, parameters, paras);
        return cs.executeBatch(conn, one.getSql(), paras, insertFast, batchSize, pkeys, keyValues);
    }

    private SQLContext getBatchSqlContextBySqlSource(String sqlSource, List<Map<String, Object>> parameters, List<Object[]> paras) {
        SQLContext one = null;
        if (CollectionUtils.isNotEmpty(parameters)) {
            for (Map<String, Object> map : parameters) {
                SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, map);
                if (one == null) {
                    one = parsedSql;
                }
                paras.add(parsedSql.getValues().toArray());
            }
        }
        if (one == null) {
            one = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, null);
        }
        return one;
    }

    @Override
    public int insert(Connection conn, List<String> pkeys, Map<String, Object> keyValues, String sqlSource, Map<String, Object> paramters) {
        SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, paramters);
        return cs.execute(conn, parsedSql.getSql(), parsedSql.getValues().toArray(), false, pkeys, keyValues);
    }

    @Override
    public int execute(Connection conn, String sqlSource, Map<String, Object> paramters) {
        SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, paramters);
        return cs.execute(conn, parsedSql.getSql(), parsedSql.getValues().toArray());
    }

    @Override
    public <T> Page<T> selectPage(Connection conn, long start, int limit, Class<T> beanClass, String sqlSource,
                                  Map<String, Object> paramters) {
        SQLContext parsedPageCountSql = TemplateRender.getTemplateHandler().getParsedPageSqlSource(sqlSource, paramters);
//        SQLContext parsedPageListSql = TemplateRender.getTemplateHandler().getParsedPageListSql(sqlSource, paramters);
        String pageSql = DBUtils.doGetDialect(conn, false).sqlPageList(parsedPageCountSql.getListSql(), start, limit);
        Object[] objects = parsedPageCountSql.getValues().toArray();
        if (pageSql != null) {
            return cs.selectRealPageRaw(conn, start, limit, beanClass, parsedPageCountSql.getCountSql(), objects,
                    pageSql, objects);
        } else {
            return cs.selectFakePageRaw(conn, start, limit, beanClass, parsedPageCountSql.getCountSql(), objects, parsedPageCountSql.getListSql(), objects);
        }
    }

    @Override
    public <T> Page<T> selectRealPageRaw(Connection conn, long start, int limit, Class<T> beanClass, String countSqlSource, Map<String, Object> countParas,
                                         String pageSqlSource, Map<String, Object> pageParas) {
        Assert.notNull(beanClass, "beanClass is null.");
        Assert.notNull(countSqlSource, "countSql is null.");
        Assert.notNull(pageSqlSource, "pageSql is null.");

        SQLContext countSqlCtx = TemplateRender.getTemplateHandler().getParsedSqlSource(countSqlSource, countParas);
        SQLContext pageListSqlCtx = TemplateRender.getTemplateHandler().getParsedSqlSource(pageSqlSource, pageParas);
        return cs.selectRealPageRaw(conn, start, limit, beanClass, countSqlCtx.getSql(), countSqlCtx.getValues().toArray(),
                pageListSqlCtx.getSql(), pageListSqlCtx.getValues().toArray());
    }

    @Override
    public <T> Page<T> selectFakePageRaw(Connection conn, long start, int limit, Class<T> beanClass, String countSqlSource, Map<String, Object> countParas,
                                         String listSqlSource, Map<String, Object> listParas) {
        Assert.notNull(beanClass, "beanClass is null.");
        Assert.notNull(countSqlSource, "countSql is null.");
        Assert.notNull(listSqlSource, "listSql is null.");

        SQLContext countSqlCtx = TemplateRender.getTemplateHandler().getParsedSqlSource(countSqlSource, countParas);
        SQLContext pageListSqlCtx = TemplateRender.getTemplateHandler().getParsedSqlSource(listSqlSource, listParas);
        return cs.selectRealPageRaw(conn, start, limit, beanClass, countSqlCtx.getSql(), countSqlCtx.getValues().toArray(),
                pageListSqlCtx.getSql(), pageListSqlCtx.getValues().toArray());
    }

    @Override
    public Object[] selectArray(Connection conn, String sqlSource, Map<String, Object> paramters) {
        SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, paramters);
        return cs.selectArray(conn, parsedSql.getSql(), parsedSql.getValues().toArray());
    }

    @Override
    public <T> List<T> selectList(Connection conn, Class<T> beanClass, String sqlSource, Map<String, Object> paramters) {
        SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, paramters);
        return cs.selectList(conn, beanClass, parsedSql.getSql(), parsedSql.getValues().toArray());
    }

    @Override
    public <T> List<T> selectList(Connection conn, Class<T> beanClass, String sqlSource, Map<String, Object> paramters, long start, int limit) {
        SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, paramters);
        String pageSql = DBUtils.doGetDialect(conn, false).sqlPageList(parsedSql.getSql(), start, limit);
        return cs.selectList(conn, beanClass, pageSql, parsedSql.getValues().toArray());
    }

    @Override
    public <T> T selectOne(Connection conn, Class<T> beanClass, String sqlSource, Map<String, Object> paramters) {
        SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, paramters);
        return cs.selectOne(conn, beanClass, parsedSql.getSql(), parsedSql.getValues().toArray());
    }

    @Override
    public List<Map<String, Object>> select(Connection conn, String sqlSource, Map<String, Object> paramters) {
        SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, paramters);
        return cs.select(conn, parsedSql.getSql(), parsedSql.getValues().toArray());
    }

    @Override
    public <T> void selectIterator(Connection conn, OrmIterator<T> ormIt, Class<T> returnClass, String sqlSource, Map<String, Object> paramters) {
        SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, paramters);
        Crud.getInstance().getCrudSql().selectIterator(conn, ormIt, returnClass, false, parsedSql.getSql(), parsedSql.getValues().toArray());
    }

    @Override
    public <T> void selectStream(Connection conn, OrmStream<T> ormStream, Class<T> returnClass, String sqlSource, Map<String, Object> paramters) {
        SQLContext parsedSql = TemplateRender.getTemplateHandler().getParsedSqlSource(sqlSource, paramters);
        Crud.getInstance().getCrudSql().selectStream(conn, ormStream, returnClass, false, parsedSql.getSql(), parsedSql.getValues().toArray());
    }

}
